package com.envper.security.utils;

import com.alibaba.fastjson2.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.envper.common.constant.Constants;
import com.envper.mysql.domain.dto.LoginResponseDto;
//import com.envper.common.utils.RedisUtils;
import com.envper.security.domain.Claims;
import com.envper.security.domain.LoginUser;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * DATETIME: 2024/2/7 13:41
 * USER: admin
 **/
@Component
@Slf4j
@Data
@RequiredArgsConstructor
public class JwtUtils {
    // 令牌自定义标识
    @Value("${safety.token.header}")
    private String header;

    // 令牌前缀
    @Value("${safety.token.prefix}")
    private String prefix;

    // 令牌秘钥
    @Value("${safety.token.secret}")
    private String secret;

    // 令牌有效期（默认30分钟）
    @Value("${safety.token.expireTime}")
    private Integer accessTokenExpireTime;

    @Value("${safety.token.expireTimeWeb}")
    private Integer refreshTokenExpireTime;

    private static final long MILLIS_SECOND = 1000;

    private static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;

//    private final RedisUtils redisUtils;

    public String createToken(Claims claims) {
        Algorithm algorithm = Algorithm.HMAC512(secret);
        JWTCreator.Builder builder = JWT.create();
//        builder.withJWTId(IdUtil.fastUUID());
//        builder.withExpiresAt(new Date(claims.getExpiresAt()));
//        builder.withIssuedAt(new Date(claims.getIssueAt()));
        builder.withClaim("data", JSON.toJSONString(claims));
//        builder.withPayload(JSON.toJSONString(claims));
        return builder.sign(algorithm);
    }


    public String getTokenKey(String uuid){
        return Constants.LOGIN_TOKEN_KEY + uuid;
    }

    /**
     * 构建访问令牌
     * @param loginUser 登录用户信息
     * @return 访问令牌字符串
     */
    public String buildAccessToken(LoginUser loginUser){
        // 对象转换
        String jsonString = JSON.toJSONString(loginUser);
        Claims claims = JSON.parseObject(jsonString, Claims.class);
        // 设置过期时间和发行时间
        claims.setIssueAt(loginUser.getLoginTime());
        claims.setExpiresAt(claims.getIssueAt() + accessTokenExpireTime);
        // 创建Token
        return createToken(claims);
    }

    /**
     * 构建刷新令牌
     * @param loginUser 登录用户信息
     * @return 访问令牌字符串
     */
    public String buildRefreshToken(LoginUser loginUser){
        // 对象转换
        String jsonString = JSON.toJSONString(loginUser);
        Claims claims = JSON.parseObject(jsonString, Claims.class);
        // 设置过期时间和发行时间
        claims.setIssueAt(loginUser.getLoginTime());
        claims.setExpiresAt(claims.getIssueAt() + refreshTokenExpireTime);
        // 创建Token
        return createToken(claims);
    }

    private Claims parseToken(String token){
        Algorithm algorithm = Algorithm.HMAC512(secret);
        DecodedJWT jwt = JWT
                .require(algorithm)
                .build()
                .verify(token);
        Map<String, Claim> claimMap = jwt.getClaims();
        return JSON.parseObject(claimMap.get("data").asString(), Claims.class);
    }

    /**
     * 校验是否过期和是否快过期
     * @param claims 用户凭证信息
     */
    public void verityToken(Claims claims){
        long expiresAt = claims != null ? claims.getExpiresAt() : 0L;
        long currentTime = System.currentTimeMillis();
        if(expiresAt - currentTime <= MILLIS_MINUTE_TEN){
            log.info("刷新token");
//            refreshToken(claims);
        }
    }

//    public void refreshToken(LoginUser loginUser){
//        long loginTime = System.currentTimeMillis();
//        loginUser.setLoginTime(loginTime);
//        loginUser.setExpiresAt(loginTime + accessTokenExpireTime * MILLIS_MINUTE);
//        String userKey = getTokenKey(loginUser.getToken());
//        redisUtils.setCacheObject(userKey, loginUser, accessTokenExpireTime, TimeUnit.MINUTES);
//    }

    public LoginResponseDto getLoginResponse(LoginUser loginUser){
        loginUser.setExpiresAt(System.currentTimeMillis());
        String accessToken = buildAccessToken(loginUser);
        String refreshToken = buildRefreshToken(loginUser);
        return LoginResponseDto.builder()
                .accessToken(accessToken)
                .refreshToken(refreshToken)
                .tokenType(prefix).expires(String.valueOf(loginUser.getExpiresAt() + accessTokenExpireTime))
                .build();
    }

    public Claims getClaims(HttpServletRequest request){
        if(request.getHeader(header) != null){
            String head = request.getHeader(header);
            String[] token = head.split(" ");
            if(token.length == 2 && StringUtils.hasLength(token[1])) return parseToken(token[1]);
        }
        return null;
    }
}
